package com.hhkj.study.admin.resource.service.biz.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.collect.Lists;
import com.hhkj.study.admin.resource.common.CommonValidateHandler;
import com.hhkj.study.admin.resource.entity.ResourceCourseVideo;
import com.hhkj.study.admin.resource.event.AsyncUpdateVideoEvent;
import com.hhkj.study.admin.resource.event.EventPublisher;
import com.hhkj.study.admin.resource.excel.ResourceCourseVideoExcelRes;
import com.hhkj.study.admin.resource.model.podo.ResourceCourseVideoDo;
import com.hhkj.study.admin.resource.model.podo.ResourceCourseVideoPo;
import com.hhkj.study.admin.resource.model.req.ResourceCourseVideoReq;
import com.hhkj.study.admin.resource.model.res.ResourceCourseVideoRes;
import com.hhkj.study.admin.resource.service.base.ResourceCourseVideoService;
import com.hhkj.study.admin.resource.service.biz.ResourceCourseVideoBizService;
import com.hhkj.study.admin.resource.service.extend.ResourceCourseVideoExtendService;
import com.hhkj.study.common.cache.GlobalCache;
import com.hhkj.study.common.model.res.ExcelImportResultRes;
import com.ruoyi.common.base.biz.service.biz.BaseBizServiceImpl;
import com.ruoyi.common.cont.SysConst;
import com.ruoyi.common.enums.DictCodeEnum;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.utils.excl.utils.ExcelUtils;
import com.ruoyi.common.utils.file.FileUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* ResourceCourseVideoBizServiceImpl
*
* @author SERVER
* @since 2024-09-06
*/
@Slf4j
@Service
public class ResourceCourseVideoBizServiceImpl extends BaseBizServiceImpl<ResourceCourseVideo, ResourceCourseVideoReq, ResourceCourseVideoRes, ResourceCourseVideoDo, ResourceCourseVideoPo, ResourceCourseVideoService, ResourceCourseVideoExtendService> implements ResourceCourseVideoBizService {

    @Resource
    private EventPublisher eventPublisher;

    @Resource
    private GlobalCache globalCache;

    @Resource
    private CommonValidateHandler commonValidateHandler;

    @Override
    protected void afterSave(ResourceCourseVideoReq videoReq) {
        eventPublisher.sendEvent(new AsyncUpdateVideoEvent(this, Lists.newArrayList(videoReq)));
    }

    @Override
    protected void afterUpdate(ResourceCourseVideoReq videoReq) {
        if (StrUtil.equals(videoReq.getOriginUrl(), videoReq.getUrl())) {
            return;
        }
        eventPublisher.sendEvent(new AsyncUpdateVideoEvent(this, Lists.newArrayList(videoReq)));
    }

    @Override
    protected void beforeSave(ResourceCourseVideoReq videoReq) {
        ResourceCourseVideo courseVideo = this.getExtendService().getByNameCourseType(videoReq.getName(), videoReq.getCourseType());
        if (ObjectUtil.isNotNull(courseVideo)) {
            throw new GlobalException(videoReq.getName() + "名称已存在");
        }
    }

    @Override
    protected void beforeUpdate(ResourceCourseVideoReq videoReq) {
        ResourceCourseVideo resourceCourseVideo = this.getExtendService().getByIdNotNull(videoReq.getId());
        videoReq.setOriginUrl(resourceCourseVideo.getUrl());
        if (!StrUtil.equals(resourceCourseVideo.getName(), videoReq.getName())) {
            ResourceCourseVideo courseVideo = this.getExtendService().getByNameCourseType(videoReq.getName(), videoReq.getCourseType());
            if (ObjectUtil.isNotNull(courseVideo)) {
                throw new GlobalException(videoReq.getName() + "名称已存在");
            }
        }
    }

    @Override
    protected void afterPage(List<ResourceCourseVideoRes> resourceCourseVideoRes) {
        assignVideo(resourceCourseVideoRes);
    }

    @Override
    protected void afterGetById(ResourceCourseVideoRes resourceCourseVideoRes) {
        assignVideo(Lists.newArrayList(resourceCourseVideoRes));
    }

    @Override
    protected void afterList(List<ResourceCourseVideoRes> videoResList) {
        assignVideo(videoResList);
        videoResList.sort(Comparator.comparing(ResourceCourseVideoRes::getOrderNum, Comparator.nullsFirst(Comparator.naturalOrder())));
    }


    @Override
    public boolean updatePublishFlag(ResourceCourseVideoReq req) {
        ResourceCourseVideo resourceCourseVideo = this.getExtendService().getByIdNotNull(req.getId());
        if (resourceCourseVideo.getPublishedFlag().equals(req.getPublishedFlag())) {
            throw new GlobalException(SysConst.Flag.IS.getFlag().equals(req.getPublishedFlag()) ?
                    "已上架" : "已下架");
        }
        LambdaUpdateWrapper<ResourceCourseVideo> videoUpdate = new LambdaUpdateWrapper<>();
        videoUpdate.eq(ResourceCourseVideo::getId, req.getId())
                .set(ResourceCourseVideo::getPublishedFlag, req.getPublishedFlag());
        return this.getService().update(videoUpdate);
    }

    @Override
    public void export(ResourceCourseVideoReq req, HttpServletResponse response) {
        List<ResourceCourseVideoRes> resourceCourseVideoResList = list(req);
        if (CollectionUtil.isEmpty(resourceCourseVideoResList)) {
            throw new GlobalException("没有数据");
        }
        ExcelUtils.exportExcelRuoYi(response, BeanUtil.copyToList(resourceCourseVideoResList
                        , ResourceCourseVideoExcelRes.class)
                , ResourceCourseVideoExcelRes.class, "视频列表", "视频列表");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ExcelImportResultRes importCourseVideo(MultipartFile file, HttpServletRequest request) {
        List<ResourceCourseVideoExcelRes> videoExcelResList = ExcelUtils.importExcelRuoYi(file, ResourceCourseVideoExcelRes.class, 1);
        if (CollectionUtil.isEmpty(videoExcelResList)) {
            throw new GlobalException("没有数据");
        }
        ExcelImportResultRes excelImportResultRes = commonValidateHandler.validate(videoExcelResList
                , (name, courseType) -> ObjectUtil.isNotNull(this.getExtendService().getByNameCourseType(name, courseType)));
        if (CollectionUtil.isEmpty(excelImportResultRes.getErrorList())) {
            List<ResourceCourseVideo> resourceCourseVideoList = BeanUtil.copyToList(videoExcelResList, ResourceCourseVideo.class);
            boolean isSuccess = this.getService().saveBatch(resourceCourseVideoList);
            // 筛选出没有视频时长/视频大小数据的视频 做异步处理解析信息
            List<ResourceCourseVideo> hasVideoDurationSizeVideoList = resourceCourseVideoList.stream()
                    .filter(e -> ObjectUtil.isEmpty(e.getUrl()) || ObjectUtil.isEmpty(e.getDuration()))
                    .collect(Collectors.toList());
            if (isSuccess && CollectionUtil.isNotEmpty(hasVideoDurationSizeVideoList)) {
                eventPublisher.sendEvent(new AsyncUpdateVideoEvent(this, hasVideoDurationSizeVideoList));
            }
        }
        return excelImportResultRes;
    }

    /**
     * 异步更新视频大小以及时长
     * @param asyncUpdateVideoEvent
     */
    @Async("discoveryExecutor")
    @TransactionalEventListener(fallbackExecution = true)
    public void asyncDoVideo(AsyncUpdateVideoEvent asyncUpdateVideoEvent){
        List<? extends ResourceCourseVideo> resourceVideoList = asyncUpdateVideoEvent.getResourceCourseVideoList();
        if (CollectionUtil.isEmpty(resourceVideoList)) {
            return;
        }
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        log.warn("开始处理视频...........,共计{}条数据", resourceVideoList.size());
        resourceVideoList.forEach(video -> {
            log.warn("开始异步更新视频信息，更新处理视频名为:{}", video.getName());
            Pair<Long, Long> videoInfo = FileUtils.getVideoInfo(video.getUrl());
            if (ObjectUtil.isNull(videoInfo) || videoInfo.getRight() == -1) {
                log.warn("视频文件存在问题，视频id:{}", video.getId());
                return;
            }
            video.setDuration(videoInfo.getLeft() / 1000);
            video.setSize(videoInfo.getRight());
        });
        List<ResourceCourseVideo> resourceVideoEntityList = BeanUtil.copyToList(resourceVideoList, ResourceCourseVideo.class);
        this.getService().updateBatchById(resourceVideoEntityList);
        stopWatch.stop();
        log.warn("视频处理完成，共计{}条数据，耗时:{}ms", resourceVideoList.size(), stopWatch.getTotalTimeMillis());
    }

    /**
     * 组装视频信息其他参数
     * @param videoResList
     */
    private void assignVideo(List<ResourceCourseVideoRes> videoResList) {
        if (CollectionUtil.isEmpty(videoResList)) {
            return;
        }
        Map<Long, String> dictMap = globalCache.cacheDictMap(Lists.newArrayList(DictCodeEnum.COURSE_TYPE.getCode(), DictCodeEnum.VIDEO_TYPE.getCode(), DictCodeEnum.CHAPTER_CATALOG.getCode()));
        videoResList.forEach(videoRes -> {
            videoRes.setTypeName(dictMap.get(videoRes.getType()));
            videoRes.setCourseTypeName(dictMap.get(videoRes.getCourseType()));
            videoRes.setChapterCatalogName(dictMap.get(videoRes.getChapterCatalog()));
        });
    }

}
